package com.exchange.aspect;

import com.exchange.utils.IpUtil;
import com.exchange.utils.RedisUtils;
import com.exchange.utils.result.CommonResult;
import com.exchange.utils.result.ResultCodeEnum;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/***
 *                    .::::.
 *                  .::::::::.
 *                 ::::::::::: 
 *             ..:::::::::::' 
 *           '::::::::::::'
 *             .::::::::::
 *        '::::::::::::::..
 *             ..::::::::::::.
 *           ``::::::::::::::::
 *            ::::``:::::::::'        .:::.
 *           ::::'   ':::::'       .::::::::.
 *         .::::'      ::::     .:::::::'::::.
 *        .:::'       :::::  .:::::::::' ':::::.
 *       .::'        :::::.:::::::::'      ':::::.
 *      .::'         ::::::::::::::'         ``::::.
 *  ...:::           ::::::::::::'              ``::.
 * ```` ':.          ':::::::::'                  ::::..
 *                    '.:::::'                    ':'````..
 *
 * @Author liuhai
 * @Date 2020-11-03 21:05:04
 * @Description
 */
@Configuration
@Aspect
public class LimitAspect {

    @Resource
    private RedisUtils redisService;

    @Pointcut("@annotation(visitLimit)")
    public void limit(VisitLimit visitLimit) {    }

    @Around("limit(visitLimit)")
    public CommonResult aroundLog(ProceedingJoinPoint joinPoint, VisitLimit visitLimit) throws Exception{
        try {
            Signature signature = joinPoint.getSignature();
            if (!(signature instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            HttpServletRequest request = null;

            ServletRequestAttributes attributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            request = attributes.getRequest();

            int count = visitLimit.count();
            long timeout = visitLimit.timeout();
            // IP + 请求地址
            String key = IpUtil.getIpAddr(request) + request.getRequestURI();

            CommonResult proceed = null;
            Integer maxLimit =null;
            Object value =redisService.get(key);
            if(value!=null && !value.equals("")) {
                maxLimit = Integer.valueOf(String.valueOf(value));
            }
            if (maxLimit == null) {
                redisService.set(key, "1", timeout);
                // 时间内请求在限定次数内，放行
                proceed = (CommonResult)joinPoint.proceed();
            } else if (maxLimit < count) {
                Integer i = maxLimit+1;
                redisService.set(key, i.toString(), timeout);
                // 时间内请求在限定次数内，放行
                proceed = (CommonResult)joinPoint.proceed();
            } else {
                // 时间内请求超过限定次数，拦截
                proceed = new CommonResult();
                proceed.setCode(ResultCodeEnum.FAIL.getCode());
                proceed.setMessage("请求太频繁!");
            }
            return proceed;
        } catch (Throwable throwable) {
            throw new Exception(throwable);
        }
    }
}
